#pragma once


#include <boost/mpl/aux_/na_fwd.hpp>
#include<iostream>
#include<memory>
#include <string>
#include <sys/epoll.h>
#include <sys/socket.h>
#include<functional>
#include <unistd.h>
#include "Common.hpp"
#include "Connection.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"
#include"Socket.hpp"
#include"Reactor.hpp"

using func_t = std::function<std::string(std::string &)>;//故意取引用，是协议Decode时拿到完整报文后会移除该报文，进行缓冲区修改

using namespace LogModule;
class IOService:public Connection
{
    static const int num = 1024;
public:
    IOService(int sockfd)
    {
        SetSockfd(sockfd);
        SetEvents(EPOLLIN | EPOLLET);
    }
    ~IOService()
    {}
    //回调方法
    virtual void Recver() override
    {
        //1.读取所有数据
        while(true)
        {
            char buffer[num];
            ssize_t s = ::recv(Fd(), buffer, sizeof(buffer) - 1, 0);
            if(s > 0)
            {
                //success
                Append(buffer);

            }
            else if(s == 0)
            {
                //对端关闭
                Excepter();
                break;
            }
            else 
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if(errno == EINTR)
                {
                    continue;
                }
                else 
                {
                    Excepter();
                    return;
                }
            }
        }

        //我一定把本轮数据读完了
        std::cout << InBuffer() <<std::endl;
        //用协议保证我们读到的数据是完整的
        std::string result;
        if(_on_message)
            result = _on_message(InBuffer());
        //添加应答消息，添加到outbuffer中
        Append2Out(result);

        //如何处理写的问题,outbuffer发给对方
        if(!IsOutBufferEmpty())
        {
            Sender();//方案一，直接写（推荐）
            // //方案二: 使能Writeable即可.
            // GetOwner()->EnableReadWrite(Fd(), true, true);
        }
            
    }
    virtual void Sender() override
    {
        //直接写，写事件默认就是就绪的，写满时才交给epoller
        
        while (true)
        {
            ssize_t n = send(Fd(), OutString().c_str(), OutString().size(), 0);//返回写的字节大小
            if (n > 0)
            {
                // 成功
                DisCardOutString(n); // 移除N个
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    // 缓冲区写满了，下次再来
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Excepter();
                    return;
                }
            }
        }

        // 一种：outbuffer empty
        // 一种：发送缓冲区被写满了 && outbuffer没有empty，写条件不满足，使能sockfd在epoll中的事件
        if(!IsOutBufferEmpty())
        {
            // 修改对sockfd的事件关心！-- 开启对写事件关心
            // 写事件按需设置！写事件不能长关心
            GetOwner()->EnableReadWrite(Fd(), true, true);
        }
        else{
            GetOwner()->EnableReadWrite(Fd(), true, false);
        }
        
    }
    virtual void Excepter() override
    {
        //IO读取时所有的异常都在这里处理
    }
    void RegisterOnMessage(func_t on_message)
    {
        _on_message = on_message;
    }
private:
    func_t _on_message;
};